home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / admin / chkboot < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  9.9 KB  |  382 lines

  1. #!/bin/ksh
  2. # @(#) chkboot.ksh 2.0 97/05/22
  3. # chkboot: check/write boot files (masterboot, boot0, and boot1)
  4. # 91/06/15 john h. dubois iii (john@armory.com)
  5. # 93/10/30 Added p & d options & checking for devices/files
  6. # 95/08/30 Added t option.
  7. # 96/01/20 Create tempfile in $TMP if set.
  8. # 97/05/22 Check the minor numbers of the devices to be operated on.
  9. # 97/05/22 Added fDx options.  Made messages more verbose.
  10.  
  11. name=${0##*/}
  12. Usage="Usage:
  13. $name [-fhwt] [-D<drive-num>] [-d<drive-device>] [-p<partition-device>]"
  14.  
  15. alias istrue="test 0 -ne"
  16. alias isfalse="test 0 -eq"
  17.  
  18. typeset -i write=0 err=0
  19. DriveDev=/dev/hd00
  20. PartitionDev=/dev/hd0a
  21. tell=false
  22. Debug=false
  23. Force=false
  24.  
  25. while getopts :fhwtp:d:xD: opt; do
  26.     case $opt in
  27.     h)
  28.     print -r -- \
  29. "$name: check/write boot files.
  30. $Usage
  31. $name checks the masterboot, boot0, and boot1 files against the copies
  32. stored in /etc.
  33. Options:
  34. -D<drive-num>: Check the boot files on drive <drive-num>.  This sets the
  35.     drive device to /dev/dsk/<drive-num>s0 and the partition device to
  36.     /dev/dsk/<drive-num>sa.  If -d or -p appears later on the command line,
  37.     they will override parameters set by -D.
  38. -f: Force.  Normally $name will not write to devices that do not have minor
  39.     numbers appropriate to the type of data to be written to them.  If -f
  40.     is given, this will be overridden.  This can be used to e.g. put boot
  41.     files on a non-active partition.
  42. -h: Print this help.
  43. -w: Write new copies of the boot files into the correct places on the hard
  44.     drive.
  45. -t: Tell what commands to use to write new copies of the boot files; does
  46.     not issue the commands.  This changes all errors to warnings.
  47. -d<drive-device>: Use drive-device instead of $DriveDev.
  48. -p<partition-device>: Use partition-device instead of $PartitionDev."
  49.     exit 0
  50.     ;;
  51.     t)
  52.     tell=true
  53.     write=1
  54.     ;;
  55.     w)
  56.     write=1
  57.     ;;
  58.     f)
  59.     Force=true
  60.     ;;
  61.     d)
  62.     DriveDev=$OPTARG;;
  63.     p)
  64.     PartitionDev=$OPTARG;;
  65.     D)
  66.     typeset -i driveNum=$OPTARG || exit 1
  67.     DriveDev=/dev/dsk/${driveNum}s0
  68.     PartitionDev=/dev/dsk/${driveNum}sa
  69.     ;;
  70.     x)
  71.     Debug=true;;
  72.     +?)
  73.     print -u2 "$name: options should not be preceded by a '+'."
  74.     exit 1
  75.     ;;
  76.     :)
  77.         print -r -u2 -- \
  78.         "$name: Option '$OPTARG' requires a value.  Use -h for help."
  79.         exit 1
  80.         ;;
  81.     ?) 
  82.     print -u2 "$name: $OPTARG: bad option.  Use -h for help."
  83.     exit 1
  84.     ;;
  85.     esac
  86. done
  87.  
  88. # remove args that were options
  89. let OPTIND=OPTIND-1
  90. shift $OPTIND
  91.  
  92. if [ $# -gt 0 ]; then
  93.     print -u2 "$Usage\nUse -h for help."
  94.     exit
  95. fi
  96.  
  97. # @(#) mktempfile 1.0 96/05/22
  98. # 96/01/20 jhdiii
  99.  
  100. # Usage: mkfiles name ...
  101. # Creates the named files with some attempt at security.
  102. # This will be more reliable if user do not have chown authority.
  103. # Any file that contains no / characters is created in the user's tempdir.
  104. # If TMP was not set, it is set by this function.
  105. # Returns 0 on success; prints a diagnostic message & returns 1 on failure.
  106. function mkfiles {
  107.     typeset file files
  108.     typeset -i i=0
  109.  
  110.     : ${TMP:=$TMPDIR}
  111.     : ${TMP:=/tmp}
  112.     for file; do
  113.     [[ "$file" != */* ]] && file="$TMP/$file"
  114.     files[i]=$file
  115.     let i+=1
  116.     done
  117.     set -- "${files[@]}"
  118.  
  119.     rm -f "$@" || {
  120.     # hopefully rm will have printed a more specific message.
  121.     print -u2 "Could not remove pre-existing files."
  122.     return 1
  123.     }
  124.     for file; do
  125.     # Use >> to avoid 0'ing the file in case a symlink was just made from
  126.     # the filename to something we don't want to truncate
  127.     >> "$file" || {
  128.         print -u2 "Could not create temp file $file"
  129.         return 1
  130.     }
  131.     # These are very suspicious
  132.     [ -s "$file" ] && {
  133.         print -u2 "New tempfile is not empty!!!"
  134.         return 1
  135.     }
  136.     [ -O "$file" ] || {
  137.         print -u2 "Do not own $file!!!"
  138.         return 1
  139.     }
  140.     done
  141.     # Could do some more stuff here, but anyone concerned with security should
  142.     # have chown authorization off for most users.
  143.     return 0
  144. }
  145.  
  146. # Usage: mktempfile name
  147. # Creates a tempfile name tempdir/#name$$, and sets the global mktempfile_ret
  148. # to that name.  tempdir is a temp directory in $TMP, $TMPDIR, or /tmp, and $$
  149. # is the PID of the current process.
  150. # name should be 8 characters or less, so that the resulting filename will
  151. # not be more than 14 characters long (a limit on some machines).
  152. # Returns 0 on success, prints a diagnostic message & returns 1 on failure.
  153. function mktempfile {
  154.     typeset file="#$1$$"
  155.     mkfiles "$file"
  156.     mktempfile_ret="$TMP/#$1$$"
  157. }
  158.  
  159. ### Start of kstat lib
  160. # @(#) kstat.ksh 1.0 96/11/29
  161. # 96/11/29 john h. dubois iii (john@armory.com)
  162.  
  163. # Make these print in octal
  164. typeset -i8  S_IFMT=8#0170000    # File type bitmask
  165. typeset -i8 S_IRWXU=8#0000700    # Owner perms bitmask
  166. typeset -i8 S_IRWXG=8#0000070    # Group perms bitmask
  167. typeset -i8 S_IRWXO=8#0000007    # Other perms bitmask
  168. typeset -i8 S_IFREG=8#0100000    # Reg file
  169. typeset -i8 S_IFBLK=8#0060000    # Block file
  170. typeset -i8 S_IFDIR=8#0040000    # Directory
  171. typeset -i8 S_IFCHR=8#0020000    # Char file
  172. typeset -i8 S_IFIFO=8#0010000    # Named pipe
  173. typeset -i8 S_IFNAM=8#0050000    # Special named file
  174. typeset -i8 S_IFLNK=8#0120000    # Symlink
  175. typeset -i8 S_ISUID=8#0004000    # setuid
  176. typeset -i8 S_ISGID=8#0002000    # setgid
  177. typeset -i8 S_ISVTX=8#0001000    # sticky bit
  178. typeset -i8 S_IRUSR=8#0000400    # owner read
  179. typeset -i8 S_IWUSR=8#0000200    # owner write
  180. typeset -i8 S_IXUSR=8#0000100    # owner execute
  181. typeset -i8 S_IRGRP=8#0000040    # group read
  182. typeset -i8 S_IWGRP=8#0000020    # group write
  183. typeset -i8 S_IXGRP=8#0000010    # group execute
  184. typeset -i8 S_IROTH=8#0000004    # other read
  185. typeset -i8 S_IWOTH=8#0000002    # other write
  186. typeset -i8 S_IXOTH=8#0000001    # other execute
  187.  
  188. typeset -i8 ls2mode
  189. # Usage: ls2mode ls-mode-field
  190. # Returns the file mode in ls2mode
  191. function ls2mode {
  192.     typeset perm nperm comp name=${0##*/}
  193.     typeset -i ptype ret
  194.  
  195.     typeset perm=$1
  196.  
  197.     nperm=${perm#?}
  198.     case "${perm%$nperm}" in
  199.     -) ret=S_IFREG;;
  200.     d) ret=S_IFDIR;;
  201.     l) ret=S_IFLNK;;
  202.     b) ret=S_IFBLK;;
  203.     c) ret=S_IFCHR;;
  204.     p) ret=S_IFIFO;;
  205.     s) ret=S_IFNAM;;
  206.     m) ret=S_IFNAM;;
  207.     *) print -ru2 -- "$name: unknown type character: ${perm%$nperm}"
  208.     return 2;;
  209.     esac
  210.     perm=$nperm
  211.  
  212.     for ptype in 6 3 0; do        # get perms for user, group and other
  213.     for wperm in r w xsStT; do    # strip off each mode letter
  214.         nperm=${perm#?}
  215.         # get next component of perms
  216.         comp=${perm%$nperm}
  217.         # Make sure each mode bit has one of the expected values for it
  218.         if [[ "$comp" != [-$wperm] ]]; then
  219.         print -u2 "$name: unrecognized permission character: $comp"
  220.         return 3
  221.         fi
  222.         case $comp in
  223.         -) ;;
  224.         r) ret='ret|4<<ptype';;
  225.         w) ret='ret|2<<ptype';;
  226.         [xst]) ret='ret|1<<ptype';;
  227.         esac
  228.         case $comp in
  229.         [sS]) [ ptype -eq 3 ] && ret='ret|S_ISGID' ||
  230.           ret='ret|S_ISUID'
  231.         ;;
  232.         [tT]) ret='ret|S_ISVTX';;
  233.         esac
  234.         perm=$nperm
  235.     done
  236.     done
  237.     ls2mode=ret
  238. }
  239.  
  240. typeset -i8 kstat_mode
  241. typeset -i kstat_nlink kstat_uid kstat_gid kstat_major kstat_minor kstat_size
  242.  
  243. # Usage: kstat file ...
  244. function kstat {
  245.     typeset file line IFS=" "
  246.     typeset -i n=0
  247.  
  248.     ls -lLnd "$@" | while read line; do
  249.     ls2mode $line
  250.     kstat_mode[n]=ls2mode
  251.     set -- $line
  252.     kstat_nlink[n]=$2
  253.     # store uid & gid because username and groupname may be ambiguous
  254.     kstat_uid[n]=$3
  255.     kstat_gid[n]=$4
  256.     case "$5" in
  257.     *,?*)
  258.         kstat_major[n]=${5%,*}
  259.         kstat_minor[n]=${5#*,}
  260.         kstat_size[n]=-1
  261.         ;;
  262.     *,)
  263.         kstat_major[n]=${5%,}
  264.         kstat_minor[n]=$6
  265.         kstat_size[n]=-1
  266.         shift
  267.         ;;
  268.     *)
  269.         kstat_major[n]=-1
  270.         kstat_minor[n]=-1
  271.         kstat_size[n]=$5
  272.         ;;
  273.     esac
  274.     kstat_date[n]="$6 $7 $8"
  275.     shift 8
  276.     kstat_name[n]="$*"
  277.     let n+=1
  278.     done
  279.     [ n -gt 0 ] && return 0 || return 1
  280. }
  281. ### End of kstat lib
  282.  
  283. function Error {
  284.     if $tell; then
  285.     print -u2 "Warning: $*"
  286.     else
  287.     print -u2 "Error: $*"
  288.     err=1
  289.     fi
  290. }
  291.  
  292. # Usage: chkMinor Device minorbits
  293. # Returns true if low 6 bits of Device's minor number are equal to minorbits
  294. function chkMinor {
  295.     typeset device=$1
  296.     typeset -i chkminor=$2 devminor
  297.  
  298.     kstat "$device" || Error "Could not stat $device"
  299.     $Debug && print -ru2 -- \
  300.     "Device $device: minor=$kstat_minor; want part/dev $chkminor"
  301.     devminor='kstat_minor&2#111111'
  302.     [ devminor -eq chkminor ]
  303. }
  304.  
  305. # Usage: printStatus data-type device-name exit-status
  306. function printStatus {
  307.     typeset dType=$1 devName=$2
  308.     typeset -i status=$3
  309.  
  310.     [ status -eq 0 ] && print -nr "Good " || print -nr "Bad "
  311.     print -r -- "$dType on $devName"
  312. }
  313.  
  314. isfalse write && tell=true
  315.  
  316. oldTell=$tell
  317. $Force && tell=true
  318.  
  319. chkMinor $DriveDev 8#00 ||
  320. Error "$DriveDev is not the whole physical drive device."
  321.  
  322. chkMinor $PartitionDev 8#57 ||
  323. Error "$PartitionDev is not the whole active partition device."
  324.  
  325. tell=$oldTell
  326.  
  327. for device in $DriveDev $PartitionDev; do
  328.     [ ! -w $device ] && Error "Cannot write to $device."
  329. done
  330.  
  331. for file in /etc/masterboot /etc/hdboot0 /etc/hdboot1; do
  332.     [ ! -r $file ] && Error "Cannot read $file."
  333. done
  334.  
  335. if istrue err; then
  336.     print -u2 "Aborting."
  337.     exit 1
  338. fi
  339.  
  340. if istrue write; then
  341.     # Set pairs of sourcefile,extra-dd-params
  342.     set -- masterboot of=$DriveDev hdboot0 of=$PartitionDev \
  343.     hdboot1 "of=$PartitionDev bs=1k seek=1"
  344.     while [ $# -ge 2 ]; do
  345.     if $tell; then
  346.         print "To write $1:"
  347.         print -r -- "    dd if=/etc/$1 $2"
  348.     else
  349.         print "Writing new $1..."
  350.         dd if=/etc/$1 $2
  351.     fi
  352.     shift 2
  353.     done
  354. else
  355.     # check masterboot (/etc/masterboot)
  356.     set -- `l /etc/masterboot`
  357.     size=$5
  358.     dd if=$DriveDev bs=$size count=1 2>/dev/null | cmp -s - /etc/masterboot
  359.     printStatus masterboot $DriveDev $?
  360.  
  361.     # check boot0 (/etc/hdboot0)
  362.     set -- `l /etc/hdboot0`
  363.     size=$5
  364.     dd if=$PartitionDev bs=$size count=1 2>/dev/null | cmp -s - /etc/hdboot0
  365.     printStatus boot0 $PartitionDev $?
  366.  
  367.     # check boot1 (/etc/hdboot1)
  368.     set -- `l /etc/hdboot1`
  369.     bs=1024
  370.     sz=$(( ($5 + $bs - 1) / $bs ))
  371.     # use tmp file to avoid limit on size of pipe reads
  372.     mktempfile chkboot. || {
  373.     print -u2 "$name: could not make temp file.  Exiting."
  374.     exit 1
  375.     }
  376.     tmpfile=$mktempfile_ret
  377.     dd if=$PartitionDev ibs=$bs count=$sz skip=1 of=$tmpfile 2>/dev/null
  378.     dd count=1 ibs=$5 if=$tmpfile 2>/dev/null | cmp -s - /etc/hdboot1
  379.     printStatus boot1 $PartitionDev $?
  380.     rm $tmpfile
  381. fi
  382.